package com.piece.admin.controller.oauth;

import com.piece.admin.controller.ControllerSupport;
import com.piece.admin.model.TbSysUser;
import com.piece.admin.model.TbSysUserOauth;
import com.piece.admin.service.TbSysUserOauthService;
import com.piece.admin.service.TbSysUserService;
import com.piece.core.framework.constant.ApplicationConstants;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.constant.ParamConstants;
import com.piece.core.framework.enums.OptionType;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.dto.UserDetailDTO;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.collection.MapBuilder;
import com.piece.core.framework.util.collection.MapUtil;
import com.piece.core.framework.util.math.SequenceUtil;
import com.piece.core.framework.util.object.BeanUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.framework.util.file.ImageUtil;
import com.piece.core.framework.util.security.SecurityUtil;
import com.piece.core.framework.util.security.coder.Base64Coder;
import com.piece.core.framework.util.security.coder.MD5Coder;
import com.piece.core.log.config.TenantContextHolder;
import com.piece.core.oauth.social.AuthRequestFactory;
import com.piece.core.oauth.social.AuthSocialService;
import com.piece.core.oauth.social.AuthSocialUserDTO;
import com.piece.core.web.authority.AuthorityFactory;
import com.piece.file.client.FileClientFactory;
import com.piece.file.model.TbSysFile;
import com.piece.file.service.TbSysFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhyd.oauth.model.AuthCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Controller
@Api(tags = {"第三方授权管理"})
@RequestMapping("/oauth/social")
public class OauthController extends ControllerSupport {

    @Autowired
    private AuthRequestFactory authRequestFactory;

    @Autowired(required = false)
    private AuthSocialService authSocialService;

    @Resource
    private TbSysUserService tbSysUserService;

    @Resource
    private TbSysUserOauthService tbSysUserOauthService;

    @Resource
    private AuthorityFactory authorityFactory;

    @Resource
    private FileClientFactory fileClientFactory;

    @Resource
    private TbSysFileService tbSysFileService;

    @Resource
    private SimpMessagingTemplate simpMessagingTemplate;

    @ResponseBody
    @RequestMapping("/list")
    @ApiOperation(value = "查询所有社交平台")
    public AjaxResponse list() {
        List<String> social_type = authRequestFactory.socialList();
        List<Map<String, String>> social_list = social_type.stream().map(type -> {
            Map<String, String> social_map = new HashMap<>();
            // Logo地址：https://gitee.com/justauth/justauth-oauth-logo
            switch (type) {
                case "WECHAT_ENTERPRISE":
                    social_map.put("type", "WECHAT_ENTERPRISE");
                    social_map.put("title", "企业微信");
                    social_map.put("image", "https://raw.githubusercontent.com/justauth/justauth-oauth-logo/v1.2/wechat_enterprise.png");
                    break;
                case "DINGTALK":
                    social_map.put("type", "DINGTALK");
                    social_map.put("title", "钉钉");
                    social_map.put("image", "https://raw.githubusercontent.com/justauth/justauth-oauth-logo/v1.2/dingtalk.png");
                    break;
            }

            return social_map;
        }).collect(Collectors.toList());
        return success(social_list);
    }

    @ResponseBody
    @RequestMapping("/user/{userId}")
    @ApiOperation(value = "查询用户社交账号信息")
    public AjaxResponse userSocial(@PathVariable String userId) {
        List<TbSysUserOauth> userOauth = tbSysUserOauthService.getOauthByUid(Convert.toLong(userId, 0L));
        List<Map<String, String>> oauth_list = userOauth.stream().map(oauth -> {
            Map<String, String> map = new HashMap<>();
            map.put("type", oauth.getType());
            map.put("openid", oauth.getOpenid());
            return map;
        }).collect(Collectors.toList());
        return success(oauth_list);
    }

    @ResponseBody
    @RequestMapping("/redirect/{type}")
    @ApiOperation(value = "跳转到社交授权页面")
    public AjaxResponse authRedirect(@PathVariable String type) {
        String session = getRequest().getParameter("session");
        String redirectUri = getRequest().getParameter("redirectUri");
        session = StringUtil.isEmpty(session) ? SequenceUtil.uuid() : session;
        MapBuilder<String, String> builder = MapUtil.builder(new HashMap<String, String>())
                .put("url", authSocialService.getAuthorizeUrl(type, redirectUri, session))
                .put("session", session);
        return success(builder.build());
    }

    @ResponseBody
    @RequestMapping("/callback/{type}")
    @ApiOperation(value = "社交授权回调")
    public void quickCallback(@PathVariable String type, AuthCallback callback) {
        AuthSocialUserDTO socialInfo = getSocialInfo(type, callback.getCode(), callback.getState());
        if (null != socialInfo) {
            simpMessagingTemplate.convertAndSendToUser(callback.getState(), "/queue/oauth/callback", socialInfo);
        }
    }

    @ResponseBody
    @RequestMapping("/quick_login/{type}")
    @ApiOperation(value = "社交快捷登录")
    public AjaxResponse quickLogin(@PathVariable String type, String code, String state) {
        return success(getSocialInfo(type, code, state));
    }

    private AuthSocialUserDTO getSocialInfo(String type, String code, String state) {
        AuthSocialUserDTO socialInfo = authSocialService.getSocialUserInfo(type, code, state);
        // 判断是否已存入数据库
        if (!tbSysUserOauthService.checkOpenIdWithType(type, socialInfo.getOpenid())) {
            socialInfo.setBind(false);
        } else {
            socialInfo.setBind(true);
            UserDetailDTO userDetail = convertUserDetail(socialInfo.getOpenid());
            String token = authorityFactory.get().autoLogin(TenantContextHolder.getTenant(), userDetail);
            socialInfo.setAccessToken(token);
        }
        return socialInfo;
    }

    @ResponseBody
    @RequestMapping("/bind_oauth/{type}")
    @ApiOperation(value = "执行第三方注册绑定")
    public AjaxResponse bindOauth(@PathVariable String type, @RequestBody AuthSocialUserDTO social) throws Exception {
        TbSysUserOauth openOauth = new TbSysUserOauth();
        BeanUtil.copyProperties(social, openOauth, null);

        String detail = getRequest().getParameter(ParamConstants.AUTHENTICATION_INFO);
        if (null == detail) {
            detail = "";
        }
        detail = Base64Coder.decode(detail.trim());
        String loginName = StringUtil.split(detail, FrameWorkConstants.SPLIT_PARAM)[0];
        String password = StringUtil.split(detail, FrameWorkConstants.SPLIT_PARAM)[1];
        TbSysUser user = tbSysUserService.findByLoginName(loginName);
        if (null == user) {
            user = wrapUser(openOauth);
            user.setGender(social.getGender());
            user.setEmail(social.getEmail());

            String salt = SecurityUtil.randomSalt();
            user.setSalt(salt);
            user.setPassword(MD5Coder.decode(loginName + password + salt));

            // 将远程图片下载到本地
            TbSysFile file = null;
            if (StringUtil.isNotEmpty(openOauth.getAvatar())) {
                byte[] bytes = ImageUtil.download(openOauth.getAvatar());
                file = fileClientFactory.get().writeToStore(bytes, "avatar", user.getLoginName() + ".jpg", bytes.length);
                openOauth.setAvatar(file.getFileId());
            }

            user = tbSysUserService.insertWithPostRole(user);
            tbSysUserService.flush();

            if (null != file) {
                file.setTable(TbSysUser.class.getSimpleName());
                file.setBusinessId(Convert.toStr(user.getUserId()));
                tbSysFileService.insertOrUpdate(file);
            }
        }

        // 保存社交用户信息
        openOauth.setUserId(user.getUserId());
        tbSysUserOauthService.insert(openOauth);

        UserDetailDTO userDetail = convertUserDetail(openOauth.getOpenid());
        String token = authorityFactory.get().autoLogin(TenantContextHolder.getTenant(), userDetail);
        Map<String, String> param = new HashMap<>();
        param.put("token", token);
        param.put("url", applicationProperties.getValue(ApplicationConstants.SYSTEM_ADDRESS));
        return success(param);
    }

    @ResponseBody
    @RequestMapping("/unbind_oauth/{type}")
    @ApiOperation(value = "解绑第三方账号")
    public AjaxResponse unbindOauth(@PathVariable String type) {
        String openid =getRequest().getParameter("openid");
        try {
            TbSysUserOauth oauth = tbSysUserOauthService.getOauthByOpenIdWithType(type, openid);
            if (null != oauth) {
                tbSysUserOauthService.delete(oauth.getOauthId());
            }

            return success();
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    private UserDetailDTO convertUserDetail(String openId) {
        UserDetailDTO userDetail = new UserDetailDTO("");
        userDetail.setOpenID(openId);
        return userDetail;
    }

    private TbSysUser wrapUser(TbSysUserOauth openOauth) {
        TbSysUser user = new TbSysUser();
        user.setUserName(openOauth.getNickname());
        user.setStatus(StatusType.NORMAL.getCode());
        user.setUserType(OptionType.OPTION.getCode());
        if (StringUtil.isNotBlank(openOauth.getAvatar())) {
            user.setAvatar(openOauth.getAvatar());
        }
        return user;
    }
}
